#!/usr/bin/env python
# -*- coding: utf-8 -*-

""" 字句解析モジュール """

import re
import shlex

class LexerReader:
	""" テキスト読み込みクラス """
	def __init__(self, filepath):
		""" コンストラクタ """
		self.shlex = shlex.shlex(open(filepath, "r"))
		self.shlex.commenters = []
		self.token = "dummy"
		self.shlex.whitespace = [" ", "\t"]
		self.filepath = filepath
		self.column = 1 # ソース列番号（トークン単位）
	def read(self):
		""" トークン読み込み """
		self.token = self.shlex.get_token()
		if self.token == '\n':
			self.column = 1
		else:
			self.column += 1
		return self.token
	def unread(self, str):
		""" トークンを戻す """
		self.shlex.push_token(str)
		self.column -= 1
	def isEof(self):
		""" ファイルの終端に達したかどうか """
		return self.token == self.shlex.eof
	def getLineno(self):
		""" 現在の行番号を返す """
		return self.shlex.lineno
	def getColumnNo(self):
		""" 現在の列番号を返す """
		return self.column
	def getFilename(self):
		return self.filepath


from tokentype import TokenType
class Lexer:
	""" 字句解析クラス """
	def __init__(self, lexReader):
		""" コンストラクタ """
		self.lexReader = lexReader # ファイル読み込みオブジェクト
		self.token  = ""           # トークン
		self.type   = 0            # トークンの種類
		self.reserved = { # 予約語テーブル
			"true":   TokenType.TRUE,
			"false":  TokenType.FALSE,
			"if":     TokenType.IF,
			"else":   TokenType.ELSE,
			"elif":   TokenType.ELIF,
			"select": TokenType.SELECT,
			"def":    TokenType.DEF,
			"fun":    TokenType.FUN,
			"goto":   TokenType.GOTO,
			"call":   TokenType.CALL
		}
	def getToken(self):
		return self.token
	def getLineno(self):
		return self.lexReader.getLineno()
	def getColumnno(self):
		return self.lexReader.getColumnNo()
	def getFinename(self):
		return self.lexReader.getFilename()
	def unread(self, token):
		""" トークンを戻す """
		self.lexReader.unread(token)
	def advance(self):
		""" 次のトークンに進める """
		token = self.lexReader.read()
		if self.lexReader.isEof():
			return False
		elif token == "\n":
			self.type = TokenType.CRLF
			self.token = token
		elif re.match('".+"', token):
			self.type  = TokenType.QUOTES
			self.token = token
		elif token == '+':
			token = self.lexReader.read()
			if token == '=':
				self.type = TokenType.IADD
			else:
				self.type = '+'
				self.lexReader.unread(token)
		elif token == '-':
			token = self.lexReader.read()
			if token == '=':
				self.type = TokenType.ISUB
			else:
				self.type = '-'
				self.lexReader.unread(token)
		elif token == '*':
			token = self.lexReader.read()
			if token == '=':
				self.type = TokenType.IMUL
			else:
				self.type = '*'
				self.lexReader.unread(token)
		elif token == '/':
			token = self.lexReader.read()
			if token == '=':
				self.type = TokenType.IDIV
			elif token == '/':
				# コメント文字列
				while True:
					token = self.lexReader.read()
					if token == '\n' or self.lexReader.isEof():
						#self.advance()
						self.type = TokenType.CRLF
						self.token = '\n'
						break
			else:
				self.type = '/'
				self.lexReader.unread(token)
		elif token == '<':
			token = self.lexReader.read()
			if token == '=':
				self.type = TokenType.LE
			else:
				self.type = '<'
				self.lexReader.unread(token)
		elif token == '>':
			token = self.lexReader.read()
			if token == '=':
				self.type = TokenType.GE
			else:
				self.type = '>'
				self.lexReader.unread(token)
		elif token == '&':
			token = self.lexReader.read()
			if token == '&':
				self.type = TokenType.AND
			else:
				raise "Error"
		elif token == '|':
			token = self.lexReader.read()
			if token == '|':
				self.type = TokenType.OR
			else:
				raise "Error"
		elif token == '=':
			token = self.lexReader.read()
			if token == '=':
				self.type = TokenType.EQ
			else:
				self.type = '='
				self.lexReader.unread(token)
		elif token == '[':
			self.type = token
		elif token == ']':
			self.type = token
		elif token == '{':
			self.type = token
		elif token == '}':
			self.type = token
		elif token == '(':
			self.type = token
		elif token == ')':
			self.type = token
		elif token == ',':
			self.type = token
		elif token == '!':
			token = self.lexReader.read()
			if token == '=':
				self.type = TokenType.NE
			else:
				self.type = '!'
				self.lexReader.unread(token)
		elif re.match("\d+", token):
			self.type = TokenType.INT
			self.token = token
		elif re.match("[_a-zA-Z][_a-zA-Z\d]*", token):
			if self.reserved.has_key(token):
				self.type = self.reserved[token]
				if self.type in [TokenType.DEF, TokenType.FUN, TokenType.GOTO]:
					# ラベル・ファンクション
					token = self.lexReader.read()
					if re.match("[_a-zA-Z][_a-zA-Z\d]*", token):
						self.token = token
					else:
						raise "Error: Illigal LABEL or FUNCTION '%s'"%token
			else:
				# シンボル
				self.type  = TokenType.SYMBOL
				self.token = token
		elif token == "$":
			token = self.lexReader.read()
			if re.match("\d+", token):
				self.type  = TokenType.VAR
				self.token = "$"+token
			else:
				raise "Error"
		elif token == "#":
			token = self.lexReader.read()
			if re.match("[\da-fA-F]+", token):
				self.type  = TokenType.COLOR
				self.token = "#" + token
			else:
				raise "Error"
		elif re.match("[$][\d]+", token):
			self.type = TokenType.VAR
			self.token = token
		return True
		
